/*
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

package br.ufrj.dcc.comp2.projeto.controles;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;

import br.ufrj.dcc.comp2.projeto.modelos.Alienigena;
import br.ufrj.dcc.comp2.projeto.modelos.Componentes;
import br.ufrj.dcc.comp2.projeto.modelos.Tiro;
import br.ufrj.dcc.comp2.projeto.modelos.Vetor2D;

/**
 * Classe responsavel pelos algoritimos para detectar colis�es.
 * @author Bruno
 *
 */
public class DetectaColisao {

	/* se o step for maior q o tamanho na direção, vai dar merda... */
	private MarteAtaca ma;
	
	public DetectaColisao(MarteAtaca ma){
		this.ma = ma;
	}
	
	/**
	 * Verifica se objeto1 e objeto2 colidiram.
	 * @param objeto1
	 * @param objeto2
	 * @return True caso sim, false caso n�o.
	 */
	public boolean existeColisao(Componentes objeto1, Componentes objeto2) {
		float objeto1XMin, objeto2XMin, objeto1YMin, objeto2YMin;
		float objeto1XMax, objeto2XMax, objeto1YMax, objeto2YMax;
		
		objeto1XMin = objeto1.getPosicao().getX();
		objeto2XMin = objeto2.getPosicao().getX();
		objeto1YMin = objeto1.getPosicao().getY();
		objeto2YMin = objeto2.getPosicao().getY();
		
		objeto1XMax = objeto1.getTamanho().getX() + objeto1XMin;
		objeto2XMax = objeto2.getTamanho().getX() + objeto2XMin;
		objeto1YMax = objeto1.getTamanho().getY() + objeto1YMin;
		objeto2YMax = objeto2.getTamanho().getY() + objeto2YMin;
		
		if (((objeto1YMin >= objeto2YMin) && (objeto1YMin <= objeto2YMax))
				||(((objeto1YMax >= objeto2YMin) && (objeto1YMax <= objeto2YMax))))
		{
			if (((objeto1XMin >= objeto2XMin) && (objeto1XMin <= objeto2XMax))
					||(((objeto1XMax >= objeto2XMin) && (objeto1XMax <= objeto2XMax))))
				return true;
		}
		
		return false;
	}
	
	/**
	 * Verifica se o componente x saiu da tela.
	 * @param x
	 * @return True caso sim, false caso n�o.
	 */
	public boolean outOfBounds(Componentes x) {
		if ((x.getPosicao().getY() < 0) || (x.getPosicao().getY() > ma.getControlaJogo().getTamanhoTela().getY()) || (x.getPosicao().getX() < 0) || (x.getPosicao().getX() > ma.getControlaJogo().getTamanhoTela().getX()))
			return true;
		return false;
	}
	
	/**
	 * Controla a remo��o dos tiros que sairam da tela.
	 *
	 */
	public void detectaTiro(){
		synchronized(ma.getControlaJogo().getTiros()) {
			Iterator<Tiro> itTiro;
			
			itTiro = ma.getControlaJogo().getTiros().iterator();
			while (itTiro.hasNext()) {
				if (this.outOfBounds(itTiro.next())) {
					itTiro.remove();
				}
			}
		}
	}
	
	/**
	 * Controla a remo��o dos aliens que sairam da tela.
	 *
	 */
	public void detectaAlienigenas(){
		synchronized(ma.getControlaJogo().getAlienigenas()) {
			Iterator<Alienigena> itAlienigenas;
			itAlienigenas = ma.getControlaJogo().getAlienigenas().iterator();
			while (itAlienigenas.hasNext()) {
				if (itAlienigenas.next().getPosicao().getY() > ma.getControlaJogo().getTamanhoTela().getY()) {
					itAlienigenas.remove();
					ma.getControlaInformacoes().alienPassouDireto();
				}
			}
		}
	}
	
	/**
	 * Controla a remo��o dos tiros dos aliens que sairam da tela.
	 *
	 */
	public void detectaAlienigenasTiros(){
		Iterator<Tiro> itAlienigenasTiros;
		
		synchronized(ma.getControlaJogo().getAlienigenasTiros()) {
			itAlienigenasTiros = ma.getControlaJogo().getAlienigenasTiros().iterator();
			while (itAlienigenasTiros.hasNext()) {
				if (this.outOfBounds(itAlienigenasTiros.next())) {
					itAlienigenasTiros.remove();
				}
			}
		}
	}
	
	/**
	 * Verifica se a colisao no jogo.
	 *
	 */
	public void colidir() {
		List<Tiro> tiros;
		List<Tiro> alienigenasTiros;
		
		tiros = Collections.synchronizedList(new ArrayList<Tiro>());
		alienigenasTiros = Collections.synchronizedList(new ArrayList<Tiro>());
		
		synchronized(ma.getControlaJogo().getTiros()) {
			for (Tiro x : ma.getControlaJogo().getTiros()) {
				synchronized(ma.getControlaJogo().getAlienigenas()) {
					for (Alienigena y : ma.getControlaJogo().getAlienigenas()) {
						if (existeColisao(x, y)) {
							tiros.add(x);
							/* a partir do xMin do tiro */
							float centroTiro = x.getTamanho().getX()/2;
							/* a posicao q o tiro tem q estar pra acertar o inimigo
							 * eh praticamente 2 vezes o tamanho do tiro + tamanho do
							 * alien (totalmente pra esquerda e totalmente pra direita
							 * + espaço do alien entre)
							 */
							/* xMin do inimigo - xMin do tiro = alinhar à esquerda
							 * mas como ele pode ficar negativo (caso esteja totalmente
							 * pra fora), nós adicionamos o tamanho do tiro.
							 * aí dividimos por (tamanho do tiro*2 + tamanho do alien)
							 * pra ficarmos de 0 a 1. Aí diminuímos 0.5 pra ficar de
							 * -0.5 a 0.5
							 */
							float localTiro = (x.getPosicao().getX() - y.getPosicao().getX() + x.getTamanho().getX() + centroTiro)/(x.getTamanho().getX()*2 + y.getTamanho().getX()) - 0.5f;
		
							/* conservação do momento? não, isso não tá acontecendo aqui... */
							y.applyTorqueX(localTiro, x.getVelocidade().getY()*x.getMass());
							y.applyForce(new Vetor2D(localTiro*x.getMass() + x.getVelocidade().getX()*x.getMass(), x.getVelocidade().getY()*x.getMass()*2));
							
							if (y.getTimeToDie() == 0)
								ma.getControlaInformacoes().matouAlien();
							y.setTimeToDie(1800);
						}
					}
				}
			}
		}
		
		/* Já que ali dá comodification, eu os deleto aqui */
		synchronized(ma.getControlaJogo().getTiros()) {
			for (Tiro x : tiros) {
				ma.getControlaJogo().getTiros().remove(x);
			}
		}
		
		synchronized(ma.getControlaJogo().getAlienigenasTiros()) {
			for (Tiro x : ma.getControlaJogo().getAlienigenasTiros()) {
				if (existeColisao(x, ma.getControlaJogo().getNave())) {
					alienigenasTiros.add(x);

					float centroTiro = x.getTamanho().getX()/2;
					float localTiro = (x.getPosicao().getX() - ma.getControlaJogo().getNave().getPosicao().getX() + x.getTamanho().getX() + centroTiro)/(x.getTamanho().getX()*2 + ma.getControlaJogo().getNave().getTamanho().getX()) - 0.5f;

					ma.getControlaJogo().getNave().applyTorqueX(localTiro, x.getVelocidade().getY()*x.getMass());
					ma.getControlaJogo().getNave().applyForce(new Vetor2D(localTiro*x.getMass() + x.getVelocidade().getX()*x.getMass(), x.getVelocidade().getY()*x.getMass()));
					
					if (ma.getControlaInformacoes().perdeVida()) {
						ma.getControlaJogo().getNave().setTravaAngulo(false);
						ma.gameOver(false);
					}
				}
			}
		}
		
		synchronized(ma.getControlaJogo().getAlienigenasTiros()) {
			for (Tiro x : alienigenasTiros) {
				ma.getControlaJogo().getAlienigenasTiros().remove(x);
			}
		}
	}
	
	
}
